module UartController(
  //Host side
  iClk,               //50 MHz
  iStartTransmit,     //Start sending
  iStartAddress,      //Start address
  iEndAddress,        //End address
  oBusy,              //UART controller busy
  //UART transmitter side
  oTx,
  //Memory side
  oMemAddress,
  iMemData,
  oMemClk
);

input iClk,iStartTransmit;
input [17:0] iStartAddress;
input [17:0] iEndAddress;
output reg oBusy;
output oTx;
output reg [17:0] oMemAddress;
input [7:0] iMemData;
output reg oMemClk;

//---------------- Internal registers and wires -----------------------
reg [7:0] uartData;
reg uartStart;
wire uartBusy;
reg prevStart;
reg uartStarted;
reg [2:0] state;
reg [17:0] endAddr;

//---------------- always blocks --------------------------------------

always@(posedge iClk) begin
  prevStart <= iStartTransmit; 
  if(({prevStart,iStartTransmit} == 2'b01) && !uartStarted) begin
    uartStarted <= 1;  
    oMemAddress <= iStartAddress;
    endAddr <= iEndAddress;
    state <= 3'b000;
    oMemClk <= 0;
    oBusy <= 1;
  end
 
  if(uartStarted) begin  
    case(state)
      //Set memory address
      3'b000: begin
        oMemClk <= 1;
        state <= 3'b001;
      end
      
      //Reading Uart data
      3'b001: begin
        oMemClk <= 0;
        uartData <= iMemData;
        state <= 3'b010;
      end
      
      //Uart sending start
      3'b010: begin
        //UART_TXD_DATA <= CIRCLE_BUFF_Q[7:0];
        uartStart <= 1;
        state <= 3'b011;
      end
      
      //Set start to low
      3'b011: begin
        uartStart <= 0;
        //uclock <= 0;
        state <= 3'b100;
      end
      
      //Wait till finished sending
      3'b100: begin
        if(!uartBusy) begin
          state <= 3'b101;
        end
      end
      
      //Set next memory address
      3'b101: begin
        oMemAddress <= oMemAddress + 1'b1;
        state <= 3'b0;
        if(oMemAddress >= endAddr) begin
          uartStarted <= 0;
          oBusy <= 0;
        end
      end
    endcase
  end
end

//---------------- sub-modules --------------------------------------
AsyncTransmitter trans(
  .iClk(~iClk), 
  .iTxStart(uartStart), 
  .iTxData(uartData), 
  .oTx(oTx), 
  .oTxBusy(uartBusy)
);

endmodule
